<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\CustHub\Amqp\Producers\CrowdInviteProducer;
use App\CustHub\Amqp\Producers\SendRecordProducers;
use App\CustHub\Constants\CrowSendingConstants;
use App\CustHub\Constants\RobotApplyConstants;
use App\CustHub\Constants\RoomInviteLogTypeConstants;
use App\CustHub\Constants\SendConfigConstants;
use App\CustHub\Dto\InviteStaticDayDto;
use App\CustHub\Dto\InviteStaticRobotDto;
use App\CustHub\Dto\SmartTagStatsDto;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChSmartTagMapper;
use App\CustHub\Mapper\CrowdInviteMapper;

use App\CustHub\Model\ChCrowdInvite;
use App\CustHub\Model\ChCrowdInviteLog;
use App\CustHub\Model\ChCrowdInviteSubTask;
use App\CustHub\Model\ChRoomInviteActiveRoom;
use App\Exception\BusinessException;
use App\Robot\Service\RobotApiService;
use Carbon\Carbon;
use Hyperf\Amqp\Producer;
use Hyperf\DbConnection\Db;
use Mine\Abstracts\AbstractService;
use Hyperf\Di\Annotation\Inject;
use Mine\Exception\NormalStatusException;
use Mine\MineCollection;
use function Hyperf\Coroutine\co;

class CrowdInviteService extends AbstractService
{
    #[Inject]
    public ChRobotMapper $robotMapper;

    #[Inject]
    protected ChRobotApplyService $applyService;

    #[Inject]
    protected ChCrowSendingService $sendingService;

    #[Inject]
    protected ChRoomService $roomService;

    #[Inject]
    protected ChSendConfigService $sendConfigService;

    #[Inject]
    protected ChCorpTagService $corpTagService;


    public function __construct(CrowdInviteMapper $mapper)
    {
        $this->mapper = $mapper;
    }


    public function saveIvnite($uid, $mainUid, array $data, $id = 0)
    {
        Db::beginTransaction();
        try {
            $res = ChCrowdInvite::saveInvite($uid, $mainUid, $data, $id);
            $robotIds = !is_array($data['robot_ids']) ? json_decode($data['robot_ids'], true) : $data['robot_ids'];
            $robotIds && $this->applyService->batchApply($data['corp_id'], RobotApplyConstants::BRANCH_INVITE, [$res->id], $robotIds, false);
            //生效群
            $group_pull_data = $res->crowd_conf['group_pull_data'];
            $activeRoomData = [];
            foreach ($group_pull_data as $k=>$item) {
                $status = $k > 0 ? 0 : 1;
                $activeRoomData[] = [
                    'scheme_id' => $res->id,
                    'scheme_type' => RoomInviteLogTypeConstants::TYPE_BATCH,
                    //'robot_id' => $item['robot_id'],
                    'room_wxid' => $item['crowd_id'],
                    'genders' => json_encode($item['genders']),
                    'sort' => $item['sort'],
                    'status' => $status,
                    'created_at' => Carbon::now()->toDateTimeString(),
                    'updated_at' => Carbon::now()->toDateTimeString()
                ];
            }
            ChRoomInviteActiveRoom::insert($activeRoomData);
            //查询邀请用户
            $customTotal=0;
            if ($res->contact_type == 3) {
                //指定用户
                $customIds = $res->contact_ids;
                foreach ($customIds as $item) {
                    //生成子任务
                    $total=$this->calculateSubTaskTotal($item['robot_id'],$res->crowd_conf,$item['wxids']);
                    ChCrowdInviteSubTask::saveSubTask($res->id, $item['robot_id'], $total,$item['wxids']);
                    $customTotal+=$total;
                }
            } else {
                //查询用户
                $custom_conf = [];
                $condition=$res->condition;
                if(!empty($condition['isset']['sex']))  $condition['isset']['gender']=$condition['isset']['sex'];
                if(!empty($condition['out']['sex']))  $condition['out']['gender']=$condition['out']['sex'];
                $custom_conf['conf'][] = $condition;
                $custom_conf['type'] = $res->contact_type;
                foreach ($robotIds as $robotId) {
                    //生成子任务
                    $customIds = $this->sendingService->getContactList($robotId, $res->uid, $custom_conf);
                    $total=$this->calculateSubTaskTotal($robotId,$res->crowd_conf,$customIds);
                    ChCrowdInviteSubTask::saveSubTask($res->id, $robotId, $total);
                    $customTotal+=$total;
                }
            }
            $res->task_total=$customTotal;
            $res->save();
            //拉群机器人
            Db::commit();
            return $res;
        } catch (\Throwable $ex) {
            Db::rollBack();
            throw new BusinessException((int)$ex->getCode(), $ex->getMessage());
        }
    }

    /**
     * 计算群邀请子任务拉群任务数量
     */
    public function calculateSubTaskTotal($robotId,array $crowdConf,array $wxIds)
    {
        //1-按顺序发送全部群邀请  2-随机发送一个群邀请  3-按顺序发一个群邀请,群满发送下一个
        $pull_type=$crowdConf['pull_type'];
        $create_group=$crowdConf['create_group'];
        $total=0;
        if($pull_type==1){
//            if($create_group){
//                for($i=0;$i<count($wxIds);$i++){
//                    $total+=count($crowdConf['group_pull_data']);
//                }
//            }
            for($i=0;$i<count($wxIds);$i++){
                $total+=count($crowdConf['group_pull_data']);
            }
        }elseif($pull_type==2){
            for($i=0;$i<count($wxIds);$i++){
                $total+=1;
            }
        }elseif($pull_type==3){
            for($i=0;$i<count($wxIds);$i++){
                $total+=1;
            }
        }
        return $total;
    }


    /**
     * 循环执行邀请任务
     */
    public function loop()
    {
        ChCrowdInvite::query()->where('status', CrowSendingConstants::WAIT_SEND)
            ->where('start_time', '<', date("Y-m-d H:i:s", time()))
            ->chunk(100, function ($crowdInviteList){
                foreach ($crowdInviteList as $crowdInvite){
                    $crowdInvite->status = CrowSendingConstants::SENDING;
                    $crowdInvite->save();
                    $this->crowdProcess($crowdInvite);
                }
            });
    }


    /**
     * 处理群邀请
     */
    public function crowdProcess(ChCrowdInvite $crowdInvite)
    {
        $roomCnf = $crowdInvite->crowd_conf;
        $roomCnf['invite_guide_switch'] = $crowdInvite->is_guide;
        $roomCnf['guide_text'] = $crowdInvite->content;
        $isLastCustom=false;
        //查询子任务
        $subTaskList = ChCrowdInviteSubTask::query()->where('invite_id', $crowdInvite->id)->get()->toArray();
        $waitTime=0;
        foreach ($subTaskList as $key => $subTask) {
            $robot = container()->get(ChRobotMapper::class)->findById($subTask['robot_id']);
            if($robot->login_status !=1){
                //机器人不在线暂停
                ChCrowdInviteSubTask::query()->where('id',$subTask['id'])->update(['status'=>CrowSendingConstants::PAUSE]);
                $crowdInvite->status=CrowSendingConstants::PAUSE;
                $crowdInvite->save();
                continue;
            }
            if ($crowdInvite->contact_type == 3) {
                //指定用户
                $customIds = $subTask['custom_ids'];
                if ($customIds) {
                    $config = $this->sendConfigService->getConfig(SendConfigConstants::BRANCH_INVITE, $crowdInvite->uid,$subTask['robot_id']);
                    foreach ($customIds as $key1 => $customId) {
                        //发送间隔
                        $key1>0 && $waitTime += rand($config['send_object_interval_min'], $config['send_object_interval_max']);
                        if($key+1==count($subTaskList) && $key1+1==count($customIds)){
                            $isLastCustom=true;
                        }
                        container()->get(Producer::class)->produce(new CrowdInviteProducer(
                            [
                                'schemeId' => $crowdInvite->id,
                                'subSchemeId' => $subTask['id'],
                                'robotId' => $subTask['robot_id'],
                                'customId' => $customId,
                                'isLastCustom' => $isLastCustom,
                            ], $waitTime));
                    }
                }

            } else {
                //查询用户
                $custom_conf = [];
                $condition=$crowdInvite->condition;
                if(!empty($condition['isset']['sex']))  $condition['isset']['gender']=$condition['isset']['sex'];
                if(!empty($condition['out']['sex']))  $condition['out']['gender']=$condition['out']['sex'];
                $custom_conf['conf'][] = $condition;
                $custom_conf['type'] = $crowdInvite->contact_type;
                $customIds = $this->sendingService->getContactList($subTask['robot_id'], $crowdInvite->uid, $custom_conf);
                if ($customIds) {
                    $config = $this->sendConfigService->getConfig(SendConfigConstants::BRANCH_INVITE, $crowdInvite->uid,$subTask['robot_id']);
                    foreach ($customIds as $key1=>$customId) {
                        $key1>0 && $waitTime += rand($config['send_object_interval_min'], $config['send_object_interval_max']);
                        if($key+1==count($subTaskList) && $key1+1==count($customIds)){
                            $isLastCustom=true;
                        }
                        container()->get(Producer::class)->produce(new CrowdInviteProducer(
                            [
                                'schemeId' => $crowdInvite->id,
                                'subSchemeId' => $subTask['id'],
                                'robotId' => $subTask['robot_id'],
                                'customId' => $customId,
                                'isLastCustom' => $isLastCustom,
                            ], $waitTime));
                    }
                }
            }
        };
    }

    /**
     * @param $uid
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * 触发群邀请
     */
    public function triggerInvite($schemeId, $robotId, $customId, $roomCnf,$subSchemeId=0,$isLastCustom=false)
    {
        container()->get(RoomInviteService::class)->inviteRoomMember($schemeId, $robotId, $roomCnf, $customId, RoomInviteLogTypeConstants::TYPE_BATCH,$subSchemeId,$isLastCustom);
    }

    /**
     * 随机查找一个人数未满的群
     */
    public function getRandCrowd($crowdList, $max)
    {
        $ids = [];
        foreach ($crowdList as $item) {
            $ids[] = $item['crowd_infos']['crowd_id'];
        }
        return $this->roomService->getNotFullRobotRoomListByIds($ids, $max);
    }


    /**
     * 群邀请只能一个一个发，判断是否满，如果满了自动拉入下一个群，如果没群配置了自动创建则创建，没配置则不管了
     * @param $robotId
     * @param $crowdId
     * @param $customId
     * @return false[]
     */
    public function sendInvite($uid, $mainUid, $crowdId, $customId, $robotId, $taskId, $crowdConf, $sendConfType, $isGuide = 0, $content = [])
    {
        //获取群信息
        $crowdDetail = $this->roomService->roomDetail(['id' => $crowdId]);
        if ($crowdConf['group_user_count'] >= $crowdDetail['room_member_count']) {
            return false;
        } else {
            //未满直接拉入
            $this->toRoom($uid, $mainUid, $crowdId, $customId, $robotId, $taskId, $sendConfType, $crowdConf, $isGuide, $content);
            return true;
        }
    }


    /**
     * 拉人入群
     */
    public function toRoom($uid, $mainUid, $crowId, $customId, $robotId, $taskId, $sendConfType, $crowdConf, $isGuide = 0, $content = [])
    {
        if ($sendConfType == SendConfigConstants::BRANCH_INVITE) {
            //记录拉群日志
            ChCrowdInviteLog::query()->create([
                'main_uid' => $mainUid,
                'uid' => $uid,
                'status' => 0,
                'room_id' => $crowId,
                'contact_id' => $customId,
                'room_status' => 0,
                'robot_id' => $robotId,
                'invite_id' => $taskId,
            ]);
        }
        //发送群消息后看是否需要发送引导语
        if ($isGuide == 1) {
            $this->sendingService->sendRecord([$customId], $uid, $mainUid, [$robotId], $sendConfType, $taskId, time(), $content);
        }

        //todo 拉群...
    }


    //格式化条件邀请配置
    public function formatCondition($condition)
    {
        if (!empty($condition['out']['corp_tag_ids'])) {
            $condition['out']['corp_tag_ids_array'] = $this->corpTagService->getTagsByIds($condition['out']['corp_tag_ids']);
        }
        if (!empty($condition['isset']['corp_tag_ids'])) {
            $condition['isset']['corp_tag_ids_array'] = $this->corpTagService->getTagsByIds($condition['out']['corp_tag_ids']);
        }
        if (!empty($condition['out'])) {
            if ($condition['out']['sex'] == 0) {
                $sex = "未知";
            } else if ($condition['out']['sex'] == 1) {
                $sex = "男";
            } else if ($condition['out']['sex'] == 2) {
                $sex = "女";
            }
            $condition['out']['sex_text'] = $sex;
            if ($condition['out']['is_with_remarks'] == 1) {
                $is_with_remarks = "是";
            } else {
                $is_with_remarks = "否";
            }
            $condition['out']['is_with_remarks_text'] = $is_with_remarks;
        }
        if (!empty($condition['isset'])) {
            if ($condition['isset']['sex'] == 0) {
                $sex = "未知";
            } else if ($condition['isset']['sex'] == 1) {
                $sex = "男";
            } else if ($condition['isset']['sex'] == 2) {
                $sex = "女";
            }
            $condition['isset']['sex_text'] = $sex;
            if ($condition['isset']['is_with_remarks'] == 1) {
                $is_with_remarks = "是";
            } else {
                $is_with_remarks = "否";
            }
            $condition['isset']['is_with_remarks_text'] = $is_with_remarks;
        }
        if (!empty($condition['isset']['corp_tag_ids'])) {
            $condition['isset']['corp_tag_ids_array'] = $this->corpTagService->getTagsByIds($condition['out']['corp_tag_ids']);
        }
        return $condition;
    }


    public function exportStatistics(array $params): \Psr\Http\Message\ResponseInterface
    {
        $type = $params['type'];
        if ($type == 1) {
            $name = '分日数据';
            $dto = InviteStaticDayDto::class;
        } else {
            $dto = InviteStaticRobotDto::class;
            $name = '分页数据';
        }
        $params['page_size'] = 999;
        $data = $this->statistices($params)['items'];
        $newData = [];
        foreach ($data as $item) {
            if ($type == 1) {
                $newItem = [
                    'date' => $item['date'],
                    'in_total' => $item['in_total'],
                    'total' => $item['total'],
                    'rate' => $item['rate'] . "%",
                ];
                $newData[] = $newItem;
            } else {
                $newItem = [
                    'nickname' => $item['robot']['nickname'],
                    'in_total' => $item['in_total'],
                    'total' => $item['total'],
                    'rate' => $item['rate'] . "%",
                ];
                $newData[] = $newItem;
            }
        }
        return (new MineCollection())->export($dto, '-' . $name, $newData);
    }

    public function statistices($params)
    {
        //1分日数据  2分号数据
        $type = $params['type'];
        $robot_id = !empty($params['robot_id']) ? $params['robot_id'] : 10;
        $page_size = !empty($params['page_size']) ? $params['page_size'] : 10;;
        $startTime = !empty($params['start_time']) ? $params['start_time'] : '';
        $endTime = !empty($params['end_time']) ? $params['end_time'] : '';
        switch ($type) {
            case 1:
                $selectSql = "count(CASE WHEN room_status = 1 THEN 1 END) AS in_total,count(1) AS total,date";
                $build = ChCrowdInviteLog::query()->groupBy('date')->selectRaw($selectSql);
                if (!empty($robot_id)) {
                    $build->where('robot_id', $robot_id);
                }
                if (!empty($startTime) && !empty($endTime)) {
                    $build->whereBetween('created_at', [$startTime, $endTime]);
                }
                $page = $build->paginate((int)$page_size);
                $page->getCollection()->transform(function ($item) {
                    $item['date'] = datetime(strtotime((string)$item['date']), "Y-m-d");
                    $item['rate'] = $item['total'] == 0 ? 0 : bcdiv((string)$item['in_total'], (string)$item['total']);
                    return $item;
                });
                $list = $page->items();
                $data = [
                    'items' => $list,
                    'pageInfo' => [
                        'total' => $page->total(),
                        'currentPage' => $page->currentPage(),
                        'totalPage' => $page->lastPage(),
                    ],
                ];
                break;
            case 2:
                $selectSql = "count(CASE WHEN room_status = 1 THEN 1 END) AS in_total,count(1) AS total,robot_id";
                $build = ChCrowdInviteLog::query()->with(['robot' => function ($q) {
                    $q->select(['id', 'nickname', 'avatar', 'user_id', 'login_status', 'corp_name']);
                }])->groupBy('robot_id')->selectRaw($selectSql);
                if (!empty($robot_id)) {
                    $build->where('robot_id', $robot_id);
                }
                if (!empty($startTime) && !empty($endTime)) {
                    $build->whereBetween('created_at', [$startTime, $endTime]);
                }
                $page = $build->paginate((int)$page_size);
                $page->getCollection()->transform(function ($item) {
                    $item['rate'] = $item['total'] == 0 ? 0 : bcdiv((string)$item['in_total'], (string)$item['total']);
                    return $item;
                });
                $list = $page->items();
                $data = [
                    'items' => $list,
                    'pageInfo' => [
                        'total' => $page->total(),
                        'currentPage' => $page->currentPage(),
                        'totalPage' => $page->lastPage(),
                    ],
                ];
                break;
        }
        return $data;
    }


    /**
     * @param array $params
     * @return array
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function getActiveRoomPageList(array $params): array
    {
        $params['scheme_type'] = RoomInviteLogTypeConstants::TYPE_BATCH;

        $schemeInfo = ChCrowdInvite::query()->find($params['scheme_id']);
        if (empty($schemeInfo)) {
            throw new NormalStatusException('请选择方案');
        }

        $cfg = $schemeInfo->crowd_conf;

        $group_user_count = $cfg['group_user_count'];
        $params['group_user_count'] = $group_user_count;

        return container()->get(ChRoomInviteActiveRoomService::class)->getActiveRoomPageList($params);
    }

    /**
     * 设置进粉群状态
     * @param array $params
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function setActiveRoomStatus(array $params): bool
    {
        return container()->get(ChRoomInviteActiveRoomService::class)->setActiveRoomStatus($params, RoomInviteLogTypeConstants::TYPE_BATCH);
    }

}